// Copyright (C) Kumo inc. and its affiliates.
// Author: Jeff.li lijippy@163.com
// All rights reserved.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.
//

#include <cantor/function/signature.h>
#include <cantor/type/signature.h>
#include <turbo/crypto/md5.h>

namespace cantor {

    turbo::Status make_function_signature_no_feature(cantor::pb::catalog::FunctionDefine* meta) {
        turbo::MD5 md5;
        if (meta->is_variadic() && !meta->has_variadic_type()) {
            return turbo::data_loss_error("missing variadic type");
        }
        md5.update(meta->func_name());
        for (auto&it : meta->args()) {
            type_signature(it, md5);
        }
        if (meta->is_variadic()) {
            md5.update("VARIADIC");
            type_signature(meta->variadic_type(), md5);
        }

        auto r = md5.final();
        meta->set_base_signature(r.digest());
        meta->set_base_id(r.high());
        return turbo::OkStatus();
    }

    uint64_t make_function_args_signature(const cantor::pb::catalog::FunctionResolveArgs &args) {
        turbo::MD5 md5;
        md5.update(args.func_name());
        for (auto&it : args.args()) {
            type_signature(it, md5);
        }

        auto r = md5.final();
        return r.high();
    }

    turbo::Status make_function_signature(cantor::pb::catalog::FunctionDefine* meta) {
        TURBO_RETURN_NOT_OK(make_function_signature_no_feature(meta));
        turbo::MD5 md5;
        if (meta->is_variadic() && !meta->has_variadic_type()) {
            return turbo::data_loss_error("missing variadic type");
        }
        type_signature(meta->ret_type(), md5);
        md5.update(meta->func_name());
        for (auto&it : meta->args()) {
            type_signature(it, md5);
        }
        if (meta->is_variadic()) {
            md5.update("VARIADIC");
            type_signature(meta->variadic_type(), md5);
        }

        md5.update(cantor::pb::catalog::FunctionFeature_Name(meta->feature()));

        auto r = md5.final();
        meta->set_signature(r.digest());
        meta->set_id(r.high());
        return turbo::OkStatus();
    }
}  // namespace cantor
